﻿// --------------------------------------------
// Last Modified: 12/22/2012
// By:administrator
// xSolon.STS - meta.ashx.cs
// --------------------------------------------

using System;
using System.IO;
using System.IdentityModel;
using System.IdentityModel.Metadata;
using System.IdentityModel.Protocols.WSTrust;
using System.Linq;
using System.Security.Claims;
using System.Web;
using System.Xml;
using System.Xml.Linq;

namespace xSolon.STS
{
    /// <summary>
    /// Summary description for meta
    /// </summary>
    public class meta : IHttpHandler
    {

        CustomSecurityTokenServiceConfiguration stsConfiguration;

        SecurityTokenService securityTokenService;

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        public void ProcessRequest(HttpContext context)
        {

            //context.Response.ContentType = "text/xml";

            stsConfiguration = new CustomSecurityTokenServiceConfiguration();
            
            securityTokenService = new CustomSecurityTokenService(stsConfiguration);

            var elem = GetFederationMetadata();

            var raw = elem.ToString(SaveOptions.DisableFormatting);

            context.Response.Write(raw.Replace("\r", "").Replace("\n", ""));

        }

        public XElement GetFederationMetadata()
        {
            // hostname
            EndpointReference passiveEndpoint = new EndpointReference(string.Format("{0}{1}{2}", Constants.STSURL, Constants.Port, Constants.WSFedSts));

            EndpointReference activeEndpoint = new EndpointReference(string.Format("{0}{1}{2}", Constants.STSURL, Constants.Port, Constants.WSFedSts));

            // metadata document 
            EntityDescriptor entity = new EntityDescriptor(new EntityId(Constants.IssuerName));

            SecurityTokenServiceDescriptor sts = new SecurityTokenServiceDescriptor();

            entity.RoleDescriptors.Add(sts);

            // signing key
            KeyDescriptor signingKey = new KeyDescriptor(stsConfiguration.SigningCredentials.SigningKeyIdentifier);

            signingKey.Use = KeyType.Signing;

            sts.Keys.Add(signingKey);

            // claim types
            sts.ClaimTypesOffered.Add(new DisplayClaim(ClaimTypes.Email, "Email Address", "User email address"));
            sts.ClaimTypesOffered.Add(new DisplayClaim(ClaimTypes.Surname, "Surname", "User last name"));
            sts.ClaimTypesOffered.Add(new DisplayClaim(ClaimTypes.Name, "Name", "User name"));
            sts.ClaimTypesOffered.Add(new DisplayClaim(ClaimTypes.Role, "Role", "Roles user are in"));
            sts.ClaimTypesOffered.Add(new DisplayClaim("http://schemas.xmlsoap.org/claims/Group", "Group", "Groups users are in"));

            // passive federation endpoint
            sts.PassiveRequestorEndpoints.Add(passiveEndpoint);

            // supported protocols

            //Inaccessable due to protection level
            //sts.ProtocolsSupported.Add(new Uri(WSFederationConstants.Namespace));
            sts.ProtocolsSupported.Add(new Uri("http://docs.oasis-open.org/wsfed/federation/200706"));

            // add passive STS endpoint
            sts.SecurityTokenServiceEndpoints.Add(activeEndpoint);

            // metadata signing
            entity.SigningCredentials = stsConfiguration.SigningCredentials;

            // serialize 
            var serializer = new MetadataSerializer();
            XElement federationMetadata = null;

            using (var stream = new MemoryStream())
            {
                serializer.WriteMetadata(stream, entity);

                stream.Flush();

                stream.Seek(0, SeekOrigin.Begin);

                XmlReaderSettings readerSettings = new XmlReaderSettings
                {
                    DtdProcessing = DtdProcessing.Prohibit, // prohibit DTD processing
                    XmlResolver = null, // disallow opening any external resources
                    // no need to do anything to limit the size of the input, given the input is crafted internally and it is of small size
                };

                XmlReader xmlReader = XmlTextReader.Create(stream, readerSettings);
                federationMetadata = XElement.Load(xmlReader);
            }

            return federationMetadata;
        }

    }
}